package com.hczt.xhminiapp.common.exception;

import com.hczt.xhminiapp.common.bean.CodeMsg;
import com.hczt.xhminiapp.common.bean.RtnResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 异常统一处理
 *
 * @author sundonghe
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    private static final Integer ERROR_CODE      = -1;
    private static final String  ERROR_MSG       = "系统发生异常，请与管理员联系";
    private static final String  PARAM_ERROR_MSG = "参数传值异常，请检查";

    /**
     * 业务异常统一处理
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler(value = {BizException.class})
    @ResponseStatus(HttpStatus.OK)
    public RtnResult<String> jsonErrorHandler(HttpServletRequest request, BizException exception) {
        log.info("业务异常信息被捕获，执行【{}】时发生异常", request.getRequestURL().toString(), exception);
        return RtnResult.error(exception.getCodeMsg());
    }

    /**
     * 其他异常处理
     */
    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RtnResult<String> jsonErrorHandler(HttpServletRequest request, Throwable exception) {
        log.error("系统异常信息被捕获", exception);
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            return RtnResult.error(CodeMsg.METHOD_NOT_SUPPORT.fillArgs(request.getMethod()));
        }
        return RtnResult.error(CodeMsg.SERVER_ERROR);
    }

    /**
     * 统一处理所有的参数绑定异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public RtnResult<List<String>> jsonErrorHandler(HttpServletRequest request, BindException exception) {
        log.error("异常被捕获，执行【{}】时发生异常", request.getRequestURL().toString(), exception);
        List<ObjectError> errorList = exception.getAllErrors();
        // 拼装所有的错误信息
        String error = errorList.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
        return RtnResult.error(CodeMsg.BIND_ERROR.fillArgs(error));
    }

    /**
     * 统一处理MethodArgumentNotValidException异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public RtnResult<List<String>> jsonErrorHandler(HttpServletRequest request, MethodArgumentNotValidException exception) {
        String error = exception.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(";"));
        return RtnResult.error(CodeMsg.BIND_ERROR.fillArgs(error));
    }

    /**
     * 统一处理ConstraintViolationException异常
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public RtnResult<List<String>> jsonErrorHandler(HttpServletRequest request, ConstraintViolationException exception) {
        String error = exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
        return RtnResult.error(CodeMsg.BIND_ERROR.fillArgs(error));
    }

    /**
     * 统一处理HttpMessageNotReadableException异常
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object jsonErrorHandler(HttpServletRequest request, HttpMessageNotReadableException exception) {
        ErrorMsg<String> errorInfo = new ErrorMsg<>();
        errorInfo.setCode(ERROR_CODE);
        errorInfo.setMessage(PARAM_ERROR_MSG);
        errorInfo.setUrl(request.getRequestURL().toString());
        errorInfo.setData("Json数据格式错误");
        return errorInfo;
    }

    /**
     * 数据加密异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(value = EncryptDataInvalidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    private Object encryptDataErrorHandler(EncryptDataInvalidException e) {
        String data = "";
        try {
            data = new String(e.getData(), "utf8");
        } catch (Exception e1){
            log.error("数据加密异常，异常信息为 ", e1);
        }
        return RtnResult.error(CodeMsg.DECRYPTION_DATA_ERROR.fillArgs(data));
    }


}